package com.pzhu.user.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.pzhu.base.common.utils.exceptions.Assert;
import com.pzhu.base.common.utils.mybatisflex.LogicDeleteEntity;
import com.pzhu.base.common.utils.mybatisflex.LogicDeleteService;
import com.pzhu.base.common.utils.result.PageData;
import com.pzhu.user.dao.PermissionDAO;
import com.pzhu.user.dao.RoleDAO;
import com.pzhu.user.dao.RolePermissionDAO;
import com.pzhu.user.dao.UserRoleDAO;
import com.pzhu.user.domain.entity.Permission;
import com.pzhu.user.domain.entity.Role;
import com.pzhu.user.domain.entity.RolePermission;
import com.pzhu.user.domain.entity.UserRole;
import com.pzhu.user.domain.ro.RoleCreateRO;
import com.pzhu.user.domain.ro.RoleSearchRO;
import com.pzhu.user.domain.ro.RoleUpdateRO;
import com.pzhu.user.domain.vo.RolePermissionCollectionVo;
import com.pzhu.user.domain.vo.RoleSearchVO;
import com.pzhu.user.domain.vo.converter.RoleVOConverter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

@Service
@RequiredArgsConstructor
@Slf4j
public class RoleService {

    private final RoleDAO roleDAO;
    private final RoleVOConverter roleVoConverter;
    private final UserRoleDAO userRoleDAO;
    private final RolePermissionDAO rolePermissionDAO;
    private final PermissionDAO permissionDAO;


    /**
     * 搜索
     *
     * @param roleSearchRo 角色搜索请求
     * @return {@link PageData }<{@link RoleSearchVO }>
     */
    public PageData<RoleSearchVO> search(RoleSearchRO roleSearchRo) {
        Page<Role> page = Page.of(roleSearchRo.getPage(), roleSearchRo.getSize());
        Page<Role> rolePage = roleDAO.search(page, roleSearchRo);
        return roleVoConverter.convert(rolePage);
    }

    /**
     * 信息
     *
     * @param roleId 角色ID
     * @return {@link RoleSearchVO }
     */
    public RoleSearchVO info(Long roleId) {
        Role role = roleDAO.selectRoleById(roleId);
        Assert.assertNotNull(role, "角色不存在！");
        return roleVoConverter.convert(role);
    }

    /**
     * 节省
     *
     * @param roleCreateRo 角色创建需求
     * @return {@link Long }
     */
    @Transactional
    public Long save(RoleCreateRO roleCreateRo) {
        boolean result = roleDAO.existCode(roleCreateRo.getRoleCode());
        Assert.assertFalse(result, "角色编码已经存在！");
        Role role = Role.builder()
                .code(roleCreateRo.getRoleName())
                .roleDesc(roleCreateRo.getRoleDesc())
                .build();
        roleDAO.save(role);
        return role.getId();
    }

    /**
     * 更新
     *
     * @param roleId 角色ID
     * @param roleUpdateRo 角色更新要求
     * @return boolean
     */
    public boolean update(Long roleId, @Valid RoleUpdateRO roleUpdateRo) {
        Role role = roleDAO.selectRoleById(roleId);
        Assert.assertNotNull(role, "角色不存在！");
        Role updateEntity = new Role();
        updateEntity.setId(roleId);
        updateEntity.setUpdatedAt(LocalDateTime.now());
        updateEntity.setCode(roleUpdateRo.getRoleCode());
        updateEntity.setRoleDesc(roleUpdateRo.getRoleDesc());
        return false;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Long roleId) {
        Role role = roleDAO.selectRoleById(roleId);
        Assert.assertNotNull(role, "角色不存在！");
        return roleDAO.logicDelete(role);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<Long> roleIds) {
        return roleDAO.logicDeleteByIds(roleIds);
    }

    public RolePermissionCollectionVo getUserAllRoles(Long userId) {
        List<UserRole>  userRoleList =  userRoleDAO.listByUserId(userId);
        List<Long> roleIdList = userRoleList.stream().map(UserRole::getRoleId).toList();
        List<RolePermission> rolePermissionList =  rolePermissionDAO.listByRoleIds(roleIdList);
        List<Long> permissionIds = rolePermissionList.stream().map(RolePermission::getPermissionId).toList();
        List<String> roleCodeList = getCodeList(roleDAO, roleIdList, Role::getCode);
        List<String> permissionCodeList = getCodeList(permissionDAO, permissionIds, Permission::getCode);
        return RolePermissionCollectionVo.builder()
                .roleList(roleCodeList)
                .permissionList(permissionCodeList)
                .build();
    }


    private <T extends LogicDeleteEntity> List<String> getCodeList(LogicDeleteService<T> dao, List<Long> ids, Function<T,String> getCodeFun){
        return Optional.of(ids)
                .filter(CollectionUtils::isNotEmpty)
                .map(dao::listByIds)
                .orElse(Collections.emptyList())
                .stream().map(getCodeFun).toList();
    }
}
